<template>
    <div v-show="visible">
        <ul class="upload-content">
            <li v-for="(row, i) in renderedRows" :key="i + 'upload'" class="upload-item">
                <div class="file-name" @click="handleFilePreview(row)">
                    <i class="iconfont icon-a-icon-Theattachment"></i>
                    {{ row?.documentName }}
                </div>
                <div class="time">{{ row?.addTime }}</div>
                <div class="size">{{ row?.fileSize | size }}</div>
                <div class="name" v-if="type === 'view'">{{ row?.addName }}</div>
                <div class="status">
                    <span v-if="row.status === 'success' && row.isShowStatus" class="text-success"><i class="el-icon-success"></i>上传成功</span>
                    <span v-else-if="row.status === 'waiting'"><i class="el-icon-info"></i>等待上传</span>
                    <span v-else-if="row.status === 'uploading'">{{ speed(row) | size }}/s</span>
                    <span v-else-if="row.status === 'error'"></span>
                    <span v-else-if="row.status === 'cancel'">{{ row.progress }}% 已暂停 <i class="el-icon-close"></i></span>
                    <span v-else-if="row.status === 'abort'">已取消<i class="el-icon-refresh-left"></i></span>
                </div>
                <div class="operate">
                    <i class="iconfont icon-icon-delete" @click="handleDelete(i)"></i>
                </div>
                <div class="mask" :style="progressStyle(row)"></div>
            </li>
        </ul>
        <!-- 预览 -->
        <preview v-model="dialogVisible" :previewData="previewData" :preview-rows="previewRows"></preview>
    </div>
</template>

<script>
// import { getDocByPath } from '../api/doc';
// import { batchDeleteAnnex } from '../api/oss';
import { throttle } from 'lodash';
import { Vue, Component, Prop, Emit, Inject, Ref, Watch } from 'vue-property-decorator';
import Preview from '../preview';

@Component({
    components: {
        Preview
    }
}) // eslint-disable-line
export default class UploadManager extends Vue {
    @Prop() type;

    @Ref() body;

    expand = true;

    scrollThrottleFn = throttle(this.onScroll, 50);

    startIdx = 0;

    status = '';

    newRows = [];

    dialogVisible = false;

    previewData = {};

    timer = null;

    get statusText() {
        if (!this.status) return '全部';
        return this.statuses.find((v) => v.value === this.status)?.label;
    }

    statuses = [
        { label: '全部', value: '' },
        { label: '成功', value: 'success' },
        { label: '失败', value: 'error' },
        { label: '暂停', value: 'cancel' },
        { label: '取消', value: 'abort' },
        { label: '等待', value: 'waiting' }
    ];

    realtimeQueue = [];

    get rows() {
        // 获取上传队列的结果
        return this.$oss.queue || [];
    }

    set rows(value) {
        this.newRows = value;
    }

    get filterRows() {
        let data = this.newRows.length > 0 ? this.newRows : this.rows;
        this.status && (data = data.filter((v) => v.status === this.status));
        return data;
    }

    get renderedRows() {
        // const data = this.filterRows.slice(this.startIdx, this.startIdx + 8);
        return this.filterRows;
    }

    /* 预览列表数据处理 */
    get previewRows() {
        return this.renderedRows.map((val) => {
            return {
                ...val,
                name: val.documentName,
                url: val.urlAddress
                // docId: val.annexId
            };
        });
    }

    get uploadingNum() {
        return this.rows.filter((v) => {
            return ['uploading', 'cancel'].includes(v.status);
        }).length;
    }

    get completeNum() {
        return this.rows.filter((v) => {
            return ['success'].includes(v.status);
        }).length;
    }

    get visible() {
        return this.$oss.visible;
    }

    set visible(value) {
        if (!value) {
            this.expand = value;
        }
        this.$oss.visible = value;
    }

    get listHeightStyle() {
        return {
            height: Math.max(0, 48 * this.filterRows.length - 480) + 'px'
        };
    }

    selectedStatusCls(row) {
        return this.status === row.value ? 'selected' : '';
    }

    errorCls(row) {
        return row.status === 'error' ? this.$style.error : '';
    }

    progressStyle(row) {
        if (['uploading', 'cancel'].includes(row.status)) {
            return {
                width: `${row.progress}%`
            };
        }
        return {};
    }

    onGoto(row) {
        if (row.params.path === row.params.actualPath) {
            this.$router.push({ path: '/docs', query: { id: row.params.parentId } });
        } else {
            // getDocByPath(row.params.actualPath).then((data) => {
            //     if (!data) {
            //         this.$message.error('文档不存在');
            //         return;
            //     }
            //     if (data?.type !== 'dir') {
            //         this.$message.error('请输入文件夹地址');
            //         return;
            //     }
            //     this.$router.push({ path: this.$route.path, query: { id: data?.docId } });
            // });
        }
    }

    onCancel(row) {
        try {
            this.$oss.cancel(row);
        } catch (err) {
            this.$message.error(err && err.message);
        }
    }

    onAbort(row) {
        try {
            this.$oss.abort(row);
        } catch (err) {
            this.$message.error(err && err.message);
        }
    }

    onResume(row) {
        this.$oss.resume(row);
    }

    onResumeAll() {
        const target = this.$oss.queue.filter((v) => ['error', 'abort'].includes(v.status));
        target.forEach((v) => {
            this.onResume(v);
        });
    }

    onCancelAll() {
        const target = this.$oss.queue.filter((v) => ['uploading', 'waiting'].includes(v.status));
        target.forEach((v) => {
            if (v.status === 'uploading') {
                this.onCancel(v);
            } else {
                v.status = 'cancel';
            }
        });
    }

    onStartAll() {
        const target = this.$oss.queue.filter((v) => ['cancel'].includes(v.status));
        target.forEach((v) => {
            this.onResume(v);
        });
    }

    onScroll() {
        if (!this.body) return;
        const top = this.body.scrollTop;
        this.startIdx = Math.floor(top / 48);
    }

    onSelectStatus(row) {
        this.status = row.value || '';
        this.startIdx = 0;
    }

    onClearAll() {
        const hasUploading = this.rows.some((v) => {
            return ['uploading'].includes(v.status);
        });
        if (hasUploading) {
            this.$message.info('尚有正在上传的文件，请选暂停所有上传');
            return;
        }
        this.$confirm('确定清空上传列表，清空后不可恢复?', '提示')
            .then(() => {
                this.$oss.queue = [];
            })
            .catch(() => {
                // ignore
            });
    }

    speed(row) {
        if (row?.status !== 'uploading') return 0;
        const id = row?.checkpoint?.uploadId;
        const item = this.realtimeQueue.find((v) => v.id === id);
        return item?.speed || 0;
    }

    created() {
        const handler = setInterval(() => {
            const items = this.renderedRows.filter((v) => v.status === 'uploading');
            const queue = [];
            items.forEach((v) => {
                if (!v.checkpoint) return;
                const { partSize, doneParts, uploadId } = v.checkpoint;
                const len = doneParts.length * partSize;
                const item = this.realtimeQueue.find((w) => w.id === uploadId) || { id: uploadId, done: len, speed: 0 };
                item.speed = len - item.done;
                item.done = len;
                // queue.push(item);
                queue.unshift(item);
            });
            this.realtimeQueue = queue;
        }, 1000);
        this.$once('hook:beforeDestroy', function () {
            if (handler) clearInterval(handler);
        });
    }

    // 删除当前文件
    handleDelete(i) {
        this.$hbPlusConfirm({ message: '确定删除当前上传文件，删除后不可恢复?' }).then(async () => {
            this.$oss.queue.splice(i, 1);
            this.$emit('handle-remove');
            // let res = await batchDeleteAnnex([annexId]);
        });
    }

    /* 处理预览文件 */
    handleFilePreview(row) {
        this.previewData = {
            ...row,
            name: row.documentName,
            url: row.urlAddress
        };
        this.dialogVisible = true;
    }

    @Watch('$oss.queue', { deep: true, immediate: true })
    onRowsChange(newVal) {
        this.$nextTick(() => {
            let data = newVal?.map((val) => {
                let params = {};
                if (val?.annexId) {
                    params = val;
                } else if (val?.resp) {
                    const res = val.resp?.data?.response;
                    const { documentName, fileSize, annexId, addName, addTime, urlAddress } = res?.annex;
                    params = {
                        documentName,
                        fileSize,
                        url: res.url,
                        urlAddress,
                        annexId: annexId,
                        addName: addName,
                        addTime: addTime,
                        progress: val.progress,
                        status: val.status,
                        isShowStatus: val.isShowStatus
                    };
                } else {
                    params = {
                        documentName: val.params.name,
                        progress: val.progress,
                        status: val.status
                    };
                }
                return params;
            });
            this.rows = data;

            /* 处理上传成功状态 2秒后隐藏 */
            this.timer = setTimeout(() => {
                this.$oss.queue.forEach((val) => {
                    if (val?.isShowStatus === true) val.isShowStatus = false;
                });
                data.forEach((val) => {
                    if (val?.isShowStatus === true) val.isShowStatus = false;
                });
            }, 2000);
        });
    }

    beforeDestroy() {
        this.timer = null;
    }
}
</script>

<style lang="scss" module>
@import '../vars.scss';
/* @import '../../../../assets/styles/rem.css'; //rem布局 */

.container {
    border-radius: 2px;
    box-shadow: 0 0 6px 0 rgb(98 107 132 / 20%);
    background-color: $bg-color;
    width: 100%;
    max-width: 600px;
}

.header {
    padding: 8px 12px;
    color: $text-secondary-color;
    border-bottom: 1px solid $border-split-color;
    display: flex;
    justify-content: space-between;
}

.body {
    font-size: 12px;
    max-height: 384px;
    overflow-y: auto;
    position: relative;
}

.list {
    list-style: none;
    margin: 0;
    padding: 0;
    position: sticky;
    top: 0;
    overflow: hidden;
    left: 0;
    right: 0;
    max-height: 384px;
    background-color: #fff;
}

.item {
    display: flex;
    width: 0;
    min-width: 100%;
    align-items: center;
    height: 48px;
    padding: 0 12px;
    box-sizing: border-box;
    position: relative;

    &.error {
        background-color: $color-error-lighten-5;
    }
}

.mask {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    background-color: #e8f5ff;
    width: 0;
    z-index: -1;
    transition: all ease 0.25s;
}

.col1 {
    width: 30%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.col2 {
    width: 10%;
    padding: 0 8px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.col3 {
    width: 25%;
    padding: 0 8px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;

    &:hover {
        cursor: pointer;
    }
}

.col4 {
    width: 10%;
    min-width: 100px;
    /* flex: 1 0 auto; */
}

.actions {
    display: flex;
    width: 100%;
}

.actionText {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.actionBtn {
    flex: 0 0 auto;
}
.delete-btn {
    cursor: pointer;
}
</style>
<style lang="scss" scoped>
.upload-content {
    min-width: 380px;
    max-width: 750px;
    max-height: 150px;
    overflow: auto;
    .upload-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0 10px;
        height: 30px;
        border-radius: 4px;
        width: 100%;
        position: relative;
        &:hover {
            background: #e8f5ff;
            .file-name,
            .iconfont,
            .operate {
                color: #1678ff;
                cursor: pointer;
            }
        }
        .mask {
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            background-color: #e8f5ff;
            opacity: 0.7;
            width: 0;
            z-index: 1;
            transition: all ease 0.25s;
        }
    }
    div {
        &.file-name {
            width: 35%;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
        }

        &.time {
            color: #a3a8ad;
            min-width: 148px;
        }

        &.size,
        &.name {
            color: #a3a8ad;
            min-width: 50px;
        }

        .text-success {
            color: #00b42a;
        }
    }
    .iconfont {
        font-size: 14px;
        color: #4e5969;
        margin-right: 6px;
        display: inline-block;
    }
}
</style>
